

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/bear.jpg">
  <link rel="icon" href="/img/bear.jpg">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="Wahoyu">
  <meta name="keywords" content="">
  
    <meta name="description" content="反向追寻创建class对象并对class进行修改">
<meta property="og:type" content="article">
<meta property="og:title" content="关于反射与注解的理解与总结">
<meta property="og:url" content="http://example.com/2022/06/19/%E5%85%B3%E4%BA%8E%E5%8F%8D%E5%B0%84%E4%B8%8E%E6%B3%A8%E8%A7%A3%E7%9A%84%E7%90%86%E8%A7%A3%E4%B8%8E%E6%80%BB%E7%BB%93/index.html">
<meta property="og:site_name" content="哆啦是个梦-A Coding Bear">
<meta property="og:description" content="反向追寻创建class对象并对class进行修改">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="http://example.com/image/fanshe.jpg">
<meta property="article:published_time" content="2022-06-19T00:51:00.000Z">
<meta property="article:modified_time" content="2022-08-28T11:36:00.902Z">
<meta property="article:author" content="Wahoyu">
<meta property="article:tag" content="Java">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="http://example.com/image/fanshe.jpg">
  
  
    <meta name="referrer" content="no-referrer-when-downgrade">
  
  
  <title>关于反射与注解的理解与总结 - 哆啦是个梦-A Coding Bear</title>

  <link  rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css" />



  <link  rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css" />



<!-- 主题依赖的图标库，不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_hj8rtnfg7um.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />


  <link id="highlight-css" rel="stylesheet" href="/css/highlight.css" />
  
    <link id="highlight-css-dark" rel="stylesheet" href="/css/highlight-dark.css" />
  



  
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/bynotes/texiao/source/css/shubiao.css#.css">



  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    Fluid.ctx = Object.assign({}, Fluid.ctx)
    var CONFIG = {"hostname":"example.com","root":"/","version":"1.9.0","typing":{"enable":true,"typeSpeed":90,"cursorChar":"_","loop":false,"scope":[]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"right","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":3},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":true,"follow_dnt":true,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml"};

    if (CONFIG.web_analytics.follow_dnt) {
      var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
      Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
    }
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>

  
<meta name="generator" content="Hexo 6.2.0"></head>


<body>
  

  <header>
    

<div class="header-inner" style="height: 30vh;">
  <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>哆啦是个梦</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
          
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

  

<div id="banner" class="banner" parallax=true
     style="background: url('/img/default.png') no-repeat center center; background-size: cover;">
  <div class="full-bg-img">
    <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
      <div class="banner-text text-center fade-in-up">
        <div class="h2">
          
            <span id="subtitle" data-typed-text="关于反射与注解的理解与总结"></span>
          
        </div>

        
          
  <div class="mt-3">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-author" aria-hidden="true"></i>
        Wahoyu
      </span>
    
    
      <span class="post-meta">
        <i class="iconfont icon-date-fill" aria-hidden="true"></i>
        <time datetime="2022-06-19 08:51" pubdate>
          2022年6月19日 早上
        </time>
      </span>
    
  </div>

  <div class="mt-1">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-chart"></i>
        
          19k 字
        
      </span>
    

    
      <span class="post-meta mr-2">
        <i class="iconfont icon-clock-fill"></i>
        
        
        
          156 分钟
        
      </span>
    

    
    
      
        <span id="busuanzi_container_page_pv" style="display: none">
          <i class="iconfont icon-eye" aria-hidden="true"></i>
          <span id="busuanzi_value_page_pv"></span> 次
        </span>
        
      
    
  </div>


        
      </div>

      
    </div>
  </div>
</div>

</div>

  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar category-bar" style="margin-right: -1rem">
    





<div class="category-list">
  
  
    
    
    
    <div class="category row nomargin-x">
      <a class="category-item 
          list-group-item category-item-action col-10 col-md-11 col-xm-11" title="开发"
        id="heading-3ff3c3e26a68112c11c3e80f2a26896e" role="tab" data-toggle="collapse" href="#collapse-3ff3c3e26a68112c11c3e80f2a26896e"
        aria-expanded="true"
      >
        开发
        <span class="list-group-count">(9)</span>
        <i class="iconfont icon-arrowright"></i>
      </a>
      
      <div class="category-collapse collapse show" id="collapse-3ff3c3e26a68112c11c3e80f2a26896e"
           role="tabpanel" aria-labelledby="heading-3ff3c3e26a68112c11c3e80f2a26896e">
        
        
          
  <div class="category-post-list">
    
    
      
      
        <a href="/2022/06/05/SQL%E5%9F%BA%E7%A1%80%E8%AF%AD%E5%8F%A5%E6%97%A5%E5%B8%B8%E7%BB%83%E4%B9%A0/" title="SQL语句练习"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">SQL语句练习</span>
        </a>
      
    
      
      
        <a href="/2022/06/19/%E5%85%B3%E4%BA%8E%E5%8F%8D%E5%B0%84%E4%B8%8E%E6%B3%A8%E8%A7%A3%E7%9A%84%E7%90%86%E8%A7%A3%E4%B8%8E%E6%80%BB%E7%BB%93/" title="关于反射与注解的理解与总结"
           class="list-group-item list-group-item-action
           active">
          <span class="category-post">关于反射与注解的理解与总结</span>
        </a>
      
    
      
      
        <a href="/2022/07/06/JavaWeb/" title="基于Java Web的图书管理系统"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">基于Java Web的图书管理系统</span>
        </a>
      
    
      
      
        <a href="/2022/06/27/%E5%9F%BA%E4%BA%8EMybatis-JUL-Lombok-Maven%E7%9A%84%E5%9B%BE%E4%B9%A6%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%EF%BC%88%E5%B8%A6%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95%EF%BC%89/" title="基于Mybatis的图书管理系统"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">基于Mybatis的图书管理系统</span>
        </a>
      
    
      
      
        <a href="/2022/07/26/BookManagerSSM/" title="基于SSM+Security的图书管理系统"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">基于SSM+Security的图书管理系统</span>
        </a>
      
    
      
      
        <a href="/2022/06/10/%E7%AE%80%E5%8D%95%E7%AE%97%E6%B3%95%EF%BC%88Java%E5%AE%9E%E7%8E%B0%EF%BC%89/" title="排序与搜索算法（Java实现）"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">排序与搜索算法（Java实现）</span>
        </a>
      
    
      
      
        <a href="/2022/06/08/Java%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%AE%80%E5%8D%95%E5%AE%9E%E7%8E%B0/" title="数据结构实现（Java）"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">数据结构实现（Java）</span>
        </a>
      
    
      
      
        <a href="/2022/08/30/%E6%97%A5%E5%BF%97%E8%BF%9B%E5%8C%96%EF%BC%9AAOP+%E8%87%AA%E5%AE%9A%E4%B9%89%E6%B3%A8%E8%A7%A3%E5%AE%9E%E7%8E%B0%E6%97%A5%E5%BF%97%E8%BE%93%E5%87%BA/" title="日志进化：AOP+自定义注解实现日志输出"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">日志进化：AOP+自定义注解实现日志输出</span>
        </a>
      
    
      
      
        <a href="/2022/06/03/%E8%A7%A3%E5%86%B3Linux%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E6%AF%8F%E6%AC%A1%E8%A6%81source-etc-profile%E9%97%AE%E9%A2%98/" title="解决Linux环境变量每次要source /etc/profile问题"
           class="list-group-item list-group-item-action
           ">
          <span class="category-post">解决Linux环境变量每次要source /etc/profile问题</span>
        </a>
      
    
  </div>

        
      </div>
    </div>
  
</div>


  </aside>


    </div>

    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">关于反射与注解的理解与总结</h1>
            
            <div class="markdown-body">
              
              <p>反向追寻创建class对象并对class进行修改</p>
<span id="more"></span>



<h2 id="1、静态语言vs动态语言"><a href="#1、静态语言vs动态语言" class="headerlink" title="1、静态语言vs动态语言"></a>1、静态语言vs动态语言</h2><p>动态语言</p>
<ul>
<li>是一类在运行时可以改变其结构的语言：例如新的函数，对象，甚至代码可以被引进，已有的函数可以被删除或者其他结构上的变化。通俗点说就是在<strong>运行时代码可以根据某些条件改变自身结构</strong>。</li>
<li>主要动态语言：Object-C、C#、JavaScript、PHP、Python等。</li>
</ul>
<p>静态语言</p>
<ul>
<li><p>与动态语言相对应的，运行时结构不可变的语言就是静态语言。如 Java、C、C++。</p>
</li>
<li><p>Java不是动态语言，但是Java可以称之为 “准动态语言” 。即Java有一定的动态性，我们可以利用反射机制获得类似动态语言的特性。Java的动态性让编程的时候更加灵活。</p>
</li>
</ul>
<h3 id="1-1、反射的定义和作用概括"><a href="#1-1、反射的定义和作用概括" class="headerlink" title="1.1、反射的定义和作用概括"></a>1.1、反射的定义和作用概括</h3><p>反射就是把Java类中的各个成分映射成一个个的Java对象。即在运行状态中，对于任意一个类，都能够知道这个类所有的属性和方法，对于任意一个对象，都能调用它的任意一个方法和属性。这种动态获取信息及动态调用对象方法的功能叫Java的反射机制。</p>
<p>我们可以通过反射机制，获取到类的一些属性，包括类里面有哪些字段，方法，继承自哪个类，甚至还能获取到泛型！</p>
<p>它的权限非常高，慎重使用！</p>
<h2 id="2、类加载的机制"><a href="#2、类加载的机制" class="headerlink" title="2、类加载的机制"></a>2、类加载的机制</h2><p>在学习Java的反射机制之前，我们需要先了解一下类的加载机制，一个类是如何被加载和使用的：</p>
<p><img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg3.itboth.com%2F60%2F50%2FUrUVN3.png&refer=http%3A%2F%2Fimg3.itboth.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1637635409&t=f25ea82c853619c26897ff5b4d041d5b" srcset="/img/loading.gif" lazyload></p>
<h3 id="2-1、引出反射利用的（一一对应的）Class文件"><a href="#2-1、引出反射利用的（一一对应的）Class文件" class="headerlink" title="2.1、引出反射利用的（一一对应的）Class文件"></a>2.1、引出反射利用的（一一对应的）Class文件</h3><p>在Java程序启动时，JVM会将一部分类（class文件）先加载（并不是所有的类都会在一开始加载），通过ClassLoader将类加载，在加载过程中，会将类的信息提取出来（存放在元空间中，JDK1.8之前存放在永久代），同时也会生成一个Class对象存放在内存（堆内存），注意此Class对象只会存在一个，与加载的类唯一对应！</p>
<h3 id="2-2、手写String引出双亲委派机制"><a href="#2-2、手写String引出双亲委派机制" class="headerlink" title="2.2、手写String引出双亲委派机制"></a>2.2、手写String引出双亲委派机制</h3><p><strong>思考：</strong> 既然说和与加载的类唯一对应，那如果我们手动创建一个与JDK包名一样，同时类名也保持一致，那么JVM会加载这个类吗？</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> java.lang;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">String</span> &#123;    <span class="hljs-comment">//JDK提供的String类也是</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        System.out.println(<span class="hljs-string">&quot;我姓🐴，我叫🐴nb&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>我们发现，会出现以下报错：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs java">错误: 在类 java.lang.String 中找不到 main 方法, 请将 main 方法定义为:<br>   <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span><br></code></pre></td></tr></table></figure>

<p>但是我们明明在自己写的String类中定义了main方法啊，为什么会找不到此方法呢？实际上这是ClassLoader的<code>双亲委派机制</code>在保护Java程序的正常运行：</p>
<h3 id="2-3、类加载流程："><a href="#2-3、类加载流程：" class="headerlink" title="2.3、类加载流程："></a>2.3、类加载流程：</h3><p>①已经加载过的会在out里面</p>
<p>②AppClassLoader是自己写的类，ExtClassLoader是拓展类，BootstrapClassLoader是jdk默认自带的类.(String在Boot就被拦下来了)</p>
<p><img src="https://img-blog.csdnimg.cn/20201217213314510.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvZGV5YW5iYW8=,size_16,color_FFFFFF,t_70" srcset="/img/loading.gif" lazyload></p>
<p>实际上我们的类最开始是由BootstarpClassLoader进行加载，BootstarpClassLoader用于加载JDK提供的类，而我们自己编写的类实际上是AppClassLoader，只有BootstarpClassLoader都没有加载的类，才会让AppClassLoader来加载，因此我们自己编写的同名包同名类不会被加载，而<strong>实际要去启动的是真正的String类</strong>，也就自然找不到<code>main</code>方法了！</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Main</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        System.out.println(Main.class.getClassLoader());   <span class="hljs-comment">//查看当前类的类加载器</span><br>        System.out.println(Main.class.getClassLoader().getParent());  <span class="hljs-comment">//父加载器</span><br>        System.out.println(Main.class.getClassLoader().getParent().getParent());  <span class="hljs-comment">//爷爷加载器</span><br>        System.out.println(String.class.getClassLoader());   <span class="hljs-comment">//String类的加载器</span><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>由于BootstarpClassLoader是C++编写的，我们在Java中是获取不到的。</p>
<h2 id="3、Class对象"><a href="#3、Class对象" class="headerlink" title="3、Class对象"></a>3、Class对象</h2><h3 id="3-1、获取每个类对应的class"><a href="#3-1、获取每个类对应的class" class="headerlink" title="3.1、获取每个类对应的class"></a>3.1、获取每个类对应的class</h3><p>通过前面，我们了解了类的加载，同时会提取一个类的信息生成Class对象存放在内存中，而反射机制其实就是利用这些存放的类信息，来获取类的信息和操作类。那么如何<strong>获取到每个类对应的Class对象</strong>呢，我们可以通过以下方式（class泛型类）：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> ClassNotFoundException &#123;<br><span class="hljs-comment">//（1）使用class关键字，通过类名获取对应的class对象</span><br>    Class&lt;String&gt; clazz = String.class;<br>    Class&lt;类名&gt; clazz = 类名.class;<br>    <br><span class="hljs-comment">//（2）使用Class类的静态方法 forName()。通过包名.类名获取对应的class对象</span><br>    <span class="hljs-comment">//注意返回值是Class&lt;?&gt;  通配符</span><br>    Class&lt;?&gt; clazz2 = Class.forName(<span class="hljs-string">&quot;java.lang.String&quot;</span>);<br>    Class&lt;?&gt; clazz2 = Class.forName(<span class="hljs-string">&quot;位置.类名&quot;</span>);<br>    <br><span class="hljs-comment">//（3）通过实例对象获取对应的class对象</span><br>    Class&lt;?&gt; clazz3 = <span class="hljs-keyword">new</span> <span class="hljs-title class_">String</span>(<span class="hljs-string">&quot;cpdd&quot;</span>).getClass();  <br>    Class&lt;?&gt; clazz3 = <span class="hljs-keyword">new</span> <span class="hljs-title class_">String</span>(<span class="hljs-string">&quot;cpdd&quot;</span>).getClass();<br>&#125;<br></code></pre></td></tr></table></figure>

<p>?&gt; clazz3 &#x3D; new String(“cpdd”).getClass();<br>Class&lt;?&gt; clazz3 &#x3D; new String(“cpdd”).getClass();<br>}</p>
<p>注意Class类也是一个泛型类，只有第一种方法，能够直接获取到对应类型的Class对象，而以下两种方法使用了<code>?</code>通配符作为返回值，但是实际上都和第一个返回的是同一个对象：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java">Class&lt;String&gt; clazz = String.class;   <span class="hljs-comment">//使用class关键字，通过类名获取</span><br>Class&lt;?&gt; clazz2 = Class.forName(<span class="hljs-string">&quot;java.lang.String&quot;</span>);   <span class="hljs-comment">//使用Class类静态方法forName()，通过包名.类名获取，注意返回值是Class&lt;?&gt;</span><br>Class&lt;?&gt; clazz3 = <span class="hljs-keyword">new</span> <span class="hljs-title class_">String</span>(<span class="hljs-string">&quot;cpdd&quot;</span>).getClass();<br><br>System.out.println(clazz == clazz2);<br>System.out.println(clazz == clazz3);<br></code></pre></td></tr></table></figure>

<h3 id="3-2、基本类型的class对象本质上是包装类（表现为int）"><a href="#3-2、基本类型的class对象本质上是包装类（表现为int）" class="headerlink" title="3.2、基本类型的class对象本质上是包装类（表现为int）"></a>3.2、基本类型的class对象本质上是包装类（表现为int）</h3><p>通过比较，验证了我们一开始的结论，在<strong>JVM中每个类始终只存在一个Class对象</strong>，无论通过什么方法获取，都是一样的。现在我们再来看看这个问题：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>    Class&lt;?&gt; clazz = <span class="hljs-type">int</span>.class;   <span class="hljs-comment">//基本数据类型有Class对象吗？</span><br>    System.out.println(clazz);<span class="hljs-comment">//int</span><br>&#125;<br></code></pre></td></tr></table></figure>

<p>迷了，不是每个类才有Class对象吗，基本数据类型又不是类，这也行吗？实际上，基本数据类型也有对应的Class对象（反射操作可能需要用到），而且我们不仅可以通过class关键字获取，其实<strong>本质上是定义在对应的包装类</strong>中的：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * The &#123;<span class="hljs-doctag">@code</span> Class&#125; instance representing the primitive type</span><br><span class="hljs-comment"> * &#123;<span class="hljs-doctag">@code</span> int&#125;.</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@since</span>   JDK1.1</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@SuppressWarnings(&quot;unchecked&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Class&lt;Integer&gt;  TYPE = (Class&lt;Integer&gt;) Class.getPrimitiveClass(<span class="hljs-string">&quot;int&quot;</span>);<br><br><span class="hljs-comment">/*</span><br><span class="hljs-comment"> * Return the Virtual Machine&#x27;s Class object for the named</span><br><span class="hljs-comment"> * primitive type</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">static</span> <span class="hljs-keyword">native</span> Class&lt;?&gt; getPrimitiveClass(String name);   <span class="hljs-comment">//C++实现，并非Java定义</span><br></code></pre></td></tr></table></figure>

<p>每个包装类中（包括Void），都有一个获取原始类型Class方法，注意，<strong>getPrimitiveClass获取的是原始类型，并不是包装类型</strong>。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>    Class&lt;?&gt; clazz = <span class="hljs-type">int</span>.class;<br>    System.out.println(Integer.TYPE == <span class="hljs-type">int</span>.class);<br>&#125;<br></code></pre></td></tr></table></figure>

<p>通过对比，我们发现实际上包装类型都有一个TYPE，其实也就是基本类型的Class，那么包装类的Class和基本类的Class一样吗？</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>    System.out.println(Integer.TYPE == Integer.class);<br>&#125;<br></code></pre></td></tr></table></figure>

<p>我们发现，<strong>包装类型的Class对象 &#x3D;&#x3D; 基本类型Class对象</strong>。数组类型也是一种类型，只是编程不可见，因此我们可以直接获取数组的Class对象：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>    Class&lt;String[]&gt; clazz = String[].class;<br>    System.out.println(clazz.getName());  <span class="hljs-comment">//获取类名称（得到的是包名+类名的完整名称）</span><br>    System.out.println(clazz.getSimpleName());<br>    System.out.println(clazz.getTypeName());<br>    System.out.println(clazz.getClassLoader());   <span class="hljs-comment">//获取它的类加载器</span><br>    System.out.println(clazz.cast(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Integer</span>(<span class="hljs-string">&quot;10&quot;</span>)));   <span class="hljs-comment">//强制类型转换</span><br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="3-3、再谈instanceof"><a href="#3-3、再谈instanceof" class="headerlink" title="3.3、再谈instanceof"></a>3.3、再谈instanceof</h3><p>正常情况下，我们使用instanceof进行类型比较：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>    <span class="hljs-type">String</span> <span class="hljs-variable">str</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;&quot;</span>;<br>    System.out.println(str <span class="hljs-keyword">instanceof</span> String);<br>&#125;<br></code></pre></td></tr></table></figure>

<p>它可以判断一个对象是否为此接口或是类的实现或是子类，而现在我们有了更多的方式去判断类型：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>    <span class="hljs-type">String</span> <span class="hljs-variable">str</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;&quot;</span>;<br>    System.out.println(str.getClass() == String.class);   <span class="hljs-comment">//直接判断是否为这个类型</span><br>&#125;<br></code></pre></td></tr></table></figure>

<p>如果需要判断是否为子类或是接口&#x2F;抽象类的实现，我们可以使用<code>asSubClass()</code>方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>    <span class="hljs-type">Integer</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">10</span>;<br>    i.getClass().asSubclass(Number.class);   <span class="hljs-comment">//当Integer不是Number的子类时，会产生异常</span><br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="3-4、获取父类信息"><a href="#3-4、获取父类信息" class="headerlink" title="3.4、获取父类信息"></a>3.4、获取父类信息</h3><p>通过<code>getSuperclass()</code>方法，我们可以获取到父类的Class对象：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>    <span class="hljs-type">Integer</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">10</span>;<br>    System.out.println(i.getClass().getSuperclass());<br>&#125;<br></code></pre></td></tr></table></figure>

<p>也可以通过<code>getGenericSuperclass()</code>获取父类的原始类型的Type：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>    <span class="hljs-type">Integer</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">10</span>;<br>    <span class="hljs-type">Type</span> <span class="hljs-variable">type</span> <span class="hljs-operator">=</span> i.getClass().getGenericSuperclass();<br>    System.out.println(type);<br>    System.out.println(type <span class="hljs-keyword">instanceof</span> Class);<br>&#125;<br></code></pre></td></tr></table></figure>

<p>我们发现Type实际上是Class类的父接口，但是获取到的Type的实现并不一定是Class。</p>
<p>同理，我们也可以像上面这样获取父接口：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>    <span class="hljs-type">Integer</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">10</span>;<br>    <span class="hljs-keyword">for</span> (Class&lt;?&gt; anInterface : i.getClass().getInterfaces()) &#123;<br>        System.out.println(anInterface.getName());<br>    &#125;<br>  <br>    <span class="hljs-keyword">for</span> (Type genericInterface : i.getClass().getGenericInterfaces()) &#123;<br>        System.out.println(genericInterface.getTypeName());<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<hr>
<h2 id="4、创建类对象"><a href="#4、创建类对象" class="headerlink" title="4、创建类对象"></a>4、创建类对象</h2><p>既然我们拿到了类的定义，那么是否可以通过Class对象来创建对象、调用方法、修改变量呢？<strong>当然是可以的</strong>，那我们首先来探讨一下如何创建一个类的对象：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> InstantiationException, IllegalAccessException &#123;<br>    Class&lt;Student&gt; clazz = Student.class;<br>    <span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> clazz.newInstance();<br>    student.test();<br>&#125;<br><br><span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Student</span>&#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">test</span><span class="hljs-params">()</span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;萨日朗&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>通过使用<code>newInstance()</code>方法来创建对应类型的实例，返回泛型T，注意它会抛出InstantiationException和IllegalAccessException异常，那么什么情况下会出现异常呢？</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> InstantiationException, IllegalAccessException &#123;<br>    Class&lt;Student&gt; clazz = Student.class;<br>    <span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> clazz.newInstance();<br>    student.test();<br>&#125;<br><br><span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Student</span>&#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Student</span><span class="hljs-params">(String text)</span>&#123;<br>        <br>    &#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">test</span><span class="hljs-params">()</span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;萨日朗&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="4-1、默认无参构造"><a href="#4-1、默认无参构造" class="headerlink" title="4.1、默认无参构造"></a>4.1、默认无参构造</h3><p>当类默认的构造方法被带参构造覆盖时，会出现InstantiationException异常，因为<code>newInstance()</code>只适用于默认无参构造。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> InstantiationException, IllegalAccessException &#123;<br>    Class&lt;Student&gt; clazz = Student.class;<br>    <span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> clazz.newInstance();<br>    student.test();<br>&#125;<br><br><span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Student</span>&#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-title function_">Student</span><span class="hljs-params">()</span>&#123;&#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">test</span><span class="hljs-params">()</span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;萨日朗&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="4-2、获取构造器，带参数构造"><a href="#4-2、获取构造器，带参数构造" class="headerlink" title="4.2、获取构造器，带参数构造"></a>4.2、获取构造器，带参数构造</h3><p>当默认无参构造的权限不是<code>public</code>时，会出现IllegalAccessException异常，表示我们无权去调用默认构造方法。在JDK9之后，不再推荐使用<code>newInstance()</code>方法了，而是使用我们接下来要介绍到的，通过<strong>获取构造器，来实例化对象</strong>：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException &#123;<br>    Class&lt;Student&gt; clazz = Student.class;<br>    <span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> clazz.getConstructor(String.class).newInstance(<span class="hljs-string">&quot;what&#x27;s up&quot;</span>);<br>    student.test();<br>&#125;<br><br><span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Student</span>&#123;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-title function_">Student</span><span class="hljs-params">(String str)</span>&#123;&#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">test</span><span class="hljs-params">()</span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;萨日朗&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>通过获取类的构造方法（构造器）来创建对象实例，会更加合理，我们可以使用**<code>getConstructor()</code>**<strong>方法来获取类的构造方法</strong>，同时我们需要向其中填入参数，也就是构造方法需要的类型，当然我们这里只演示了。那么，当访问权限不是public的时候呢？</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException &#123;<br>    Class&lt;Student&gt; clazz = Student.class;<br>    <span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> clazz.getConstructor(String.class).newInstance(<span class="hljs-string">&quot;what&#x27;s up&quot;</span>);<br>    student.test();<br>&#125;<br><br><span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Student</span>&#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-title function_">Student</span><span class="hljs-params">(String str)</span>&#123;&#125;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">test</span><span class="hljs-params">()</span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;萨日朗&quot;</span>);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>我们发现，当访问权限不足时，会无法找到此构造方法，那么如何找到非public的构造方法呢？</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java">Class&lt;Student&gt; clazz = Student.class;<br>Constructor&lt;Student&gt; constructor = clazz.getDeclaredConstructor(String.class);<br>constructor.setAccessible(<span class="hljs-literal">true</span>);   <span class="hljs-comment">//修改访问权限</span><br><span class="hljs-type">Student</span> <span class="hljs-variable">student</span> <span class="hljs-operator">=</span> constructor.newInstance(<span class="hljs-string">&quot;what&#x27;s up&quot;</span>);<br>student.test();<br></code></pre></td></tr></table></figure>

<h3 id="4-3、超越-private-访问构造方法"><a href="#4-3、超越-private-访问构造方法" class="headerlink" title="4.3、超越(private)访问构造方法"></a>4.3、超越(private)访问构造方法</h3><p>使用<code>getDeclaredConstructor()</code>方法可以找到类中的非public构造方法，但是在使用之前，我们需要先修改访问权限，在修改访问权限之后，就可以使用非public方法了（这意味着，反射可以无视权限修饰符访问类的内容）</p>
<hr>
<h2 id="5、调用类的方法"><a href="#5、调用类的方法" class="headerlink" title="5、调用类的方法"></a>5、调用类的方法</h2><h3 id="5-1、创建对象→找到方法→调用方法"><a href="#5-1、创建对象→找到方法→调用方法" class="headerlink" title="5.1、创建对象→找到方法→调用方法"></a>5.1、创建对象→找到方法→调用方法</h3><p>我们可以通过反射来调用类的方法（本质上还是类的实例进行调用）只是利用反射机制实现了方法的调用，我们在包下创建一个新的类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.test;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Student</span> &#123;<br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">test</span><span class="hljs-params">(String str)</span>&#123;<br>        System.out.println(<span class="hljs-string">&quot;萨日朗&quot;</span>+str);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>这次我们通过<code>forName(String)</code>来找到这个类并创建一个新的对象：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> ReflectiveOperationException &#123;<br>    Class&lt;?&gt; clazz = Class.forName(<span class="hljs-string">&quot;com.test.Student&quot;</span>);<br>    <br>    <span class="hljs-type">Object</span> <span class="hljs-variable">instance</span> <span class="hljs-operator">=</span> clazz.**newInstance**();   <span class="hljs-comment">//创建出学生对象</span><br>    <br>    <span class="hljs-type">Method</span> <span class="hljs-variable">method</span> <span class="hljs-operator">=</span> clazz.**getMethod**(<span class="hljs-string">&quot;test&quot;</span>, String.class);   <span class="hljs-comment">//通过方法名和形参类型获取类中的方法</span><br>    <br>    method.**invoke**(instance, <span class="hljs-string">&quot;what&#x27;s up&quot;</span>);   <span class="hljs-comment">//通过Method对象的invoke方法来调用方法</span><br>&#125;<br></code></pre></td></tr></table></figure>

<p>调用**<code>getMethod()</code>**<strong>方法，我们可以获取到类中所有声明为public的方法</strong>，得到一个Method对象（并不是获得所有的public，该方法使用的时候需要指定“方法名”和“形参类型”）</p>
<p>通过Method对象的<code>invoke()</code>方法（返回值就是方法的返回值，因为这里是void，返回值为null）来调用已经获取到的方法，注意传参。</p>
<h3 id="5-2、对象原来的类型被模糊"><a href="#5-2、对象原来的类型被模糊" class="headerlink" title="5.2、对象原来的类型被模糊"></a>5.2、对象原来的类型被模糊</h3><p>我们发现，利用反射之后，在一个对象从构造到方法调用，没有任何一处需要引用到对象的实际类型，我们也没有导入Student类，整个过程都是反射在代替进行操作，使得整个过程被模糊了，过多的使用反射，会极大地降低后期维护性。</p>
<h3 id="5-3、超越private访问普通方法"><a href="#5-3、超越private访问普通方法" class="headerlink" title="5.3、超越private访问普通方法"></a>5.3、超越private访问普通方法</h3><p>同构造方法一样，当出现非public方法时，我们可以通过反射来无视权限修饰符，获取非public方法并调用，现在我们将<code>test()</code>方法的权限修饰符改为private：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> ReflectiveOperationException &#123;<br>    Class&lt;?&gt; clazz = Class.forName(<span class="hljs-string">&quot;com.test.Student&quot;</span>);<br>    <span class="hljs-type">Object</span> <span class="hljs-variable">instance</span> <span class="hljs-operator">=</span> clazz.newInstance();   <span class="hljs-comment">//创建出学生对象</span><br>    <span class="hljs-type">Method</span> <span class="hljs-variable">method</span> <span class="hljs-operator">=</span> clazz.getDeclaredMethod(<span class="hljs-string">&quot;test&quot;</span>, String.class);   <span class="hljs-comment">//通过方法名和形参类型获取类中的方法</span><br>    method.setAccessible(<span class="hljs-literal">true</span>);<br><br>    method.invoke(instance, <span class="hljs-string">&quot;what&#x27;s up&quot;</span>);   <span class="hljs-comment">//通过Method对象的invoke方法来调用方法</span><br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="5-4、Method与类很相似"><a href="#5-4、Method与类很相似" class="headerlink" title="5.4、Method与类很相似"></a>5.4、Method与类很相似</h3><p>所以使用方法要么创建对象，要么类名.方法</p>
<p>Method和Constructor都和Class一样，他们存储了方法的信息，包括方法的形式参数列表，返回值，方法的名称等内容，我们可以直接<strong>通过Method对象</strong>来获取这些信息：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> ReflectiveOperationException &#123;<br>    Class&lt;?&gt; clazz = Class.forName(<span class="hljs-string">&quot;com.test.Student&quot;</span>);<br>    <span class="hljs-type">Method</span> <span class="hljs-variable">method</span> <span class="hljs-operator">=</span> clazz.getDeclaredMethod(<span class="hljs-string">&quot;test&quot;</span>, String.class);   <span class="hljs-comment">//通过方法名和形参类型获取类中的方法</span><br>    <br>    System.out.println(method.getName());   <span class="hljs-comment">//获取方法名称</span><br>    System.out.println(method.getReturnType());   <span class="hljs-comment">//获取返回值类型</span><br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="5-5、可变参数的方法→本质数组"><a href="#5-5、可变参数的方法→本质数组" class="headerlink" title="5.5、可变参数的方法→本质数组"></a>5.5、可变参数的方法→本质数组</h3><p>当方法的参数为可变参数时，我们该如何获取方法呢？实际上，我们在之前就已经提到过，可变参数实际上就是一个数组，因此我们可以直接使用数组的class对象表示：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-type">Method</span> <span class="hljs-variable">method</span> <span class="hljs-operator">=</span> clazz.getDeclaredMethod(<span class="hljs-string">&quot;test&quot;</span>, String[].class);<br></code></pre></td></tr></table></figure>

<p>反射非常强大，尤其是我们提到的越权访问，但是请一定谨慎使用，别人将某个方法设置为private一定有他的理由，如果实在是需要使用别人定义为private的方法，就必须确保这样做是安全的，在没有了解别人代码的整个过程就强行越权访问，可能会出现无法预知的错误。</p>
<hr>
<h2 id="6、修改类的属性"><a href="#6、修改类的属性" class="headerlink" title="6、修改类的属性"></a>6、修改类的属性</h2><h3 id="6-1、获取一个类的属性"><a href="#6-1、获取一个类的属性" class="headerlink" title="6.1、获取一个类的属性"></a>6.1、获取一个类的属性</h3><p>我们还可以通过反射访问一个类中定义的成员字段也可以修改一个类的对象中的成员字段值，通过<code>getField()</code>方法来获取一个类定义的指定字段：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> ReflectiveOperationException &#123;<br>    Class&lt;?&gt; clazz = Class.forName(<span class="hljs-string">&quot;com.test.Student&quot;</span>);<br>    <span class="hljs-type">Object</span> <span class="hljs-variable">instance</span> <span class="hljs-operator">=</span> clazz.newInstance();<br><br>    <span class="hljs-type">Field</span> <span class="hljs-variable">field</span> <span class="hljs-operator">=</span> clazz.getField(<span class="hljs-string">&quot;i&quot;</span>);   <span class="hljs-comment">//获取类的成员字段i</span><br>    field.set(instance, <span class="hljs-number">100</span>);   <span class="hljs-comment">//将类实例instance的成员字段i设置为100</span><br><br>    <span class="hljs-type">Method</span> <span class="hljs-variable">method</span> <span class="hljs-operator">=</span> clazz.getMethod(<span class="hljs-string">&quot;test&quot;</span>);<br>    method.invoke(instance);<br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="6-2、修改属性值"><a href="#6-2、修改属性值" class="headerlink" title="6.2、修改属性值"></a>6.2、修改属性值</h3><p>在得到Field之后，我们就可以直接通过<code>set()</code>方法为某个对象，设定此属性的值，比如上面，我们就为instance对象设定值为100，当访问private字段时，同样可以按照上面的操作进行越权访问：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> ReflectiveOperationException &#123;<br>    Class&lt;?&gt; clazz = Class.forName(<span class="hljs-string">&quot;com.test.Student&quot;</span>);<br>    <span class="hljs-type">Object</span> <span class="hljs-variable">instance</span> <span class="hljs-operator">=</span> clazz.newInstance();<br><br>    <span class="hljs-type">Field</span> <span class="hljs-variable">field</span> <span class="hljs-operator">=</span> clazz.getDeclaredField(<span class="hljs-string">&quot;i&quot;</span>);   <span class="hljs-comment">//获取类的成员属性：i</span><br>    field.setAccessible(<span class="hljs-literal">true</span>);  <span class="hljs-comment">//给予改变字段属性的权限</span><br>    field.set(instance, <span class="hljs-number">100</span>);   <span class="hljs-comment">//将类实例instance的成员字段i设置为100</span><br><br>    <span class="hljs-type">Method</span> <span class="hljs-variable">method</span> <span class="hljs-operator">=</span> clazz.getMethod(<span class="hljs-string">&quot;test&quot;</span>);<br>    <span class="hljs-comment">//获得test方法放到method（Method实例化的对象）里面</span><br>    method.invoke(instance);<br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="6-3、就连final都能修改"><a href="#6-3、就连final都能修改" class="headerlink" title="6.3、就连final都能修改"></a>6.3、就连final都能修改</h3><p>现在我们已经知道，<strong>反射几乎可以把一个类的老底都给扒出来</strong>，任何属性，任何内容，都可以被反射修改，无论权限修饰符是什么，那么，如果我的字段被标记为final呢？现在在字段<code>i</code>前面添加<code>final</code>关键字，我们再来看看效果：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-type">int</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">10</span>;<br></code></pre></td></tr></table></figure>

<p>这时，当字段为final时，就修改失败了！当然，通过反射可以直接将final修饰符直接去除，去除后，就可以随意修改内容了，我们来尝试修改Integer的value值</p>
<p>主要思想：获取成员属性之后，获取（定义该属性的字段），类似求导，对“final”进行修改,然后再退一层，对字段进行修改。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> ReflectiveOperationException &#123;<br>    <span class="hljs-type">Integer</span> <span class="hljs-variable">i</span> <span class="hljs-operator">=</span> <span class="hljs-number">10</span>;<br><br>    <span class="hljs-type">Field</span> <span class="hljs-variable">field</span> <span class="hljs-operator">=</span> Integer.class.getDeclaredField(<span class="hljs-string">&quot;value&quot;</span>);<br>    <span class="hljs-comment">//获取类的成员属性：value,进行修改</span><br><br>    <span class="hljs-type">Field</span> <span class="hljs-variable">modifiersField</span> <span class="hljs-operator">=</span> Field.class.getDeclaredField(<span class="hljs-string">&quot;modifiers&quot;</span>);<br>    <span class="hljs-comment">//这里要获取Field类的modifiers字段进行修改</span><br>    <br>    modifiersField.setAccessible(<span class="hljs-literal">true</span>);<br>    <span class="hljs-comment">//更改！定义！字段权限</span><br>    modifiersField.setInt(field,field.getModifiers()&amp;~Modifier.FINAL);  <br>    <span class="hljs-comment">//去除final标记</span><br><br>    field.setAccessible(<span class="hljs-literal">true</span>);<br>    <span class="hljs-comment">//更改字段的权限</span><br>    field.set(i, <span class="hljs-number">100</span>);   <br>    <span class="hljs-comment">//强行设置值</span><br><br>    System.out.println(i);<br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="6-4、反射可能对原数据结构进行破坏"><a href="#6-4、反射可能对原数据结构进行破坏" class="headerlink" title="6.4、反射可能对原数据结构进行破坏"></a>6.4、反射可能对原数据结构进行破坏</h3><p>我们可以发现，反射非常暴力，就连被定义为final字段的值都能强行修改，几乎能够无视一切阻拦。我们来试试看修改一些其他的类型：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> ReflectiveOperationException &#123;<br>    List&lt;String&gt; i = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br><br>    <span class="hljs-type">Field</span> <span class="hljs-variable">field</span> <span class="hljs-operator">=</span> ArrayList.class.getDeclaredField(<span class="hljs-string">&quot;size&quot;</span>);<br>    field.setAccessible(<span class="hljs-literal">true</span>);<br>    field.set(i, <span class="hljs-number">10</span>);<br><br>    i.add(<span class="hljs-string">&quot;测试&quot;</span>);   <span class="hljs-comment">//只添加一个元素</span><br>    System.out.println(i.size());  <span class="hljs-comment">//大小直接变成11</span><br>    i.remove(<span class="hljs-number">10</span>);   <span class="hljs-comment">//瞎移除都不带报错的，淦</span><br>&#125;<br></code></pre></td></tr></table></figure>

<p>实际上，整个ArrayList体系由于我们的反射操作，导致被破坏，因此它已经无法正常工作了！</p>
<p>再次强调，在进行反射操作时，必须注意是否安全，虽然拥有了创世主的能力，但是我们不能滥用，我们只能把它当做一个不得已才去使用的工具！</p>
<hr>
<h2 id="7、自定义ClassLoader加载类"><a href="#7、自定义ClassLoader加载类" class="headerlink" title="7、自定义ClassLoader加载类"></a>7、自定义ClassLoader加载类</h2><h3 id="7-1、手动-java→class"><a href="#7-1、手动-java→class" class="headerlink" title="7.1、手动.java→class"></a>7.1、手动.java→class</h3><p>我们可以自己手动将class文件加载到JVM中吗？先写好我们定义的类：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.test;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Test</span> &#123;<br>    <span class="hljs-keyword">public</span> String text;<br><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">test</span><span class="hljs-params">(String str)</span>&#123;<br>        System.out.println(text+<span class="hljs-string">&quot; &gt; 我是测试方法！&quot;</span>+str);<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>通过javac命令，手动编译一个.class文件：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs Bash">nagocoler@NagodeMacBook-Pro HelloWorld % javac src/main/java/com/test/Test.java<br></code></pre></td></tr></table></figure>

<h3 id="7-2、自己创造一个ClassLoader"><a href="#7-2、自己创造一个ClassLoader" class="headerlink" title="7.2、自己创造一个ClassLoader"></a>7.2、自己创造一个ClassLoader</h3><p>编译后，得到一个class文件，我们把它放到根目录下，然后编写一个我们自己的ClassLoader，因为普通的ClassLoader无法加载二进制文件，因此我们编写一个自己的来让它支持：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">//定义一个自己的ClassLoader</span><br><span class="hljs-keyword">static</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">MyClassLoader</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">ClassLoader</span>&#123;<br>    <span class="hljs-keyword">public</span> Class&lt;?&gt; defineClass(String name, <span class="hljs-type">byte</span>[] b)&#123;<br>        <span class="hljs-keyword">return</span> defineClass(name, b, <span class="hljs-number">0</span>, b.length);   <span class="hljs-comment">//调用protected方法，支持载入外部class文件</span><br>    &#125;<br>&#125;<br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> IOException &#123;<br>    <span class="hljs-type">MyClassLoader</span> <span class="hljs-variable">classLoader</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">MyClassLoader</span>();<br>    <span class="hljs-type">FileInputStream</span> <span class="hljs-variable">stream</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">FileInputStream</span>(<span class="hljs-string">&quot;Test.class&quot;</span>);<br>    <span class="hljs-type">byte</span>[] bytes = <span class="hljs-keyword">new</span> <span class="hljs-title class_">byte</span>[stream.available()];<br>    stream.read(bytes);<br>    Class&lt;?&gt; clazz = classLoader.defineClass(<span class="hljs-string">&quot;com.test.Test&quot;</span>, bytes);   <span class="hljs-comment">//类名必须和我们定义的保持一致</span><br>    System.out.println(clazz.getName());   <span class="hljs-comment">//成功加载外部class文件</span><br>&#125;<br></code></pre></td></tr></table></figure>

<p>现在，我们就将此class文件读取并解析为Class了，现在我们就可以对此类进行操作了（注意，我们无法在代码中直接使用此类型，因为它是我们直接加载的），我们来试试看创建一个此类的对象并调用其方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">try</span> &#123;<br>    <span class="hljs-type">Object</span> <span class="hljs-variable">obj</span> <span class="hljs-operator">=</span> clazz.newInstance();<br>    <span class="hljs-type">Method</span> <span class="hljs-variable">method</span> <span class="hljs-operator">=</span> clazz.getMethod(<span class="hljs-string">&quot;test&quot;</span>, String.class);   <span class="hljs-comment">//获取我们定义的test(String str)方法</span><br>    method.invoke(obj, <span class="hljs-string">&quot;哥们这瓜多少钱一斤？&quot;</span>);<br>&#125;<span class="hljs-keyword">catch</span> (Exception e)&#123;<br>    e.printStackTrace();<br>&#125;<br></code></pre></td></tr></table></figure>

<p>我们来试试看修改成员字段之后，再来调用此方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">try</span> &#123;<br>    <span class="hljs-type">Object</span> <span class="hljs-variable">obj</span> <span class="hljs-operator">=</span> clazz.newInstance();<br>    <span class="hljs-type">Field</span> <span class="hljs-variable">field</span> <span class="hljs-operator">=</span> clazz.getField(<span class="hljs-string">&quot;text&quot;</span>);   <span class="hljs-comment">//获取成员变量 String text;</span><br>    field.set(obj, <span class="hljs-string">&quot;华强&quot;</span>);<br>    <span class="hljs-type">Method</span> <span class="hljs-variable">method</span> <span class="hljs-operator">=</span> clazz.getMethod(<span class="hljs-string">&quot;test&quot;</span>, String.class);   <span class="hljs-comment">//获取我们定义的test(String str)方法</span><br>    method.invoke(obj, <span class="hljs-string">&quot;哥们这瓜多少钱一斤？&quot;</span>);<br>&#125;<span class="hljs-keyword">catch</span> (Exception e)&#123;<br>    e.printStackTrace();<br>&#125;<br></code></pre></td></tr></table></figure>

<p>通过这种方式，我们就可以实现外部加载甚至是网络加载一个类，只需要把类文件传递即可，这样就无需再将代码写在本地，而是动态进行传递，不仅可以一定程度上防止源代码被反编译（只是一定程度上，想破解你代码有的是方法），而且在更多情况下，我们还可以对byte[]进行加密，保证在传输过程中的安全性。</p>
<hr>
<h2 id="8、注解"><a href="#8、注解" class="headerlink" title="8、注解"></a>8、注解</h2><p>其实我们在之前就接触到注解了，比如<code>@Override</code>表示重写父类方法（当然不加效果也是一样的，此注解在编译时会被自动丢弃）注解本质上也是一个类，只不过它的用法比较特殊。</p>
<p>注解可以被标注在任意地方，包括方法上、类名上、参数上、成员属性上、注解定义上等，就像注释一样，它相当于我们对某样东西的一个标记。而与注释不同的是，注解可以通过反射在运行时获取，注解也可以选择是否保留到运行时。</p>
<h3 id="8-1、jdk自带的注解"><a href="#8-1、jdk自带的注解" class="headerlink" title="8.1、jdk自带的注解"></a>8.1、jdk自带的注解</h3><p>JDK预设了以下注解，作用于代码：</p>
<ul>
<li>@Override - 检查（仅仅是检查，不保留到运行时）该方法是否是重写方法。如果发现其父类，或者是引用的接口中并没有该方法时，会报编译错误。</li>
<li>@Deprecated - 标记过时方法。如果使用该方法，会报编译警告。</li>
<li>@SuppressWarnings - 指示编译器去忽略注解中声明的警告（仅仅编译器阶段，不保留到运行时）</li>
<li>@FunctionalInterface - Java 8 开始支持，标识一个匿名函数或函数式接口。</li>
<li>@SafeVarargs - Java 7 开始支持，忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。</li>
</ul>
<h3 id="8-2、元注解（注解的注解）"><a href="#8-2、元注解（注解的注解）" class="headerlink" title="8.2、元注解（注解的注解）"></a>8.2、元注解（注解的注解）</h3><p>元注解是作用于注解上的注解，用于我们编写自定义的注解：</p>
<ul>
<li>@Retention - 标识这个注解怎么保存，是只在代码中，还是编入class文件中，或者是在运行时可以通过反射访问。</li>
<li>@Documented - 标记这些注解是否包含在用户文档中。</li>
<li>@Target - 标记这个注解应该是哪种 Java 成员。</li>
<li>@Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)</li>
<li>@Repeatable - Java 8 开始支持，标识某注解可以在同一个声明上使用多次。</li>
</ul>
<p>看了这么多预设的注解，你们肯定眼花缭乱了，那我们来看看<code>@Override</code>是如何定义的：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Target(ElementType.METHOD)</span><br><span class="hljs-meta">@Retention(RetentionPolicy.SOURCE)</span><br><span class="hljs-keyword">public</span> <span class="hljs-meta">@interface</span> Override &#123;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>该注解由<code>@Target</code>限定为只能作用于方法上，ElementType是一个枚举类型，用于表示此枚举的作用域，一个注解可以有很多个作用域。<code>@Retention</code>表示此注解的保留策略，包括三种策略，在上述中有写到，而这里定义为只在代码中。一般情况下，自定义的注解需要定义1个<code>@Retention</code>和1-n个<code>@Target</code>。</p>
<h3 id="8-3、自己定义一个注解"><a href="#8-3、自己定义一个注解" class="headerlink" title="8.3、自己定义一个注解"></a>8.3、自己定义一个注解</h3><p>既然了解了元注解的使用和注解的定义方式，我们就来尝试定义一个自己的注解：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Target(ElementType.METHOD)</span><br><span class="hljs-meta">@Retention(RetentionPolicy.RUNTIME)</span><br><span class="hljs-keyword">public</span> <span class="hljs-meta">@interface</span> Test &#123;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>这里我们定义一个Test注解，并将其保留到运行时，同时此注解可以作用于方法或是类上：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Test</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Main</span> &#123;<br>    <span class="hljs-meta">@Test</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>        <br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>这样，一个最简单的注解就被我们创建了。</p>
<h3 id="8-4、关于注解属性的使用"><a href="#8-4、关于注解属性的使用" class="headerlink" title="8.4、关于注解属性的使用"></a>8.4、关于注解属性的使用</h3><h4 id="8-4-1、自定义属性的要点"><a href="#8-4-1、自定义属性的要点" class="headerlink" title="8.4.1、自定义属性的要点"></a>8.4.1、自定义属性的要点</h4><p>我们还可以在注解中定义<strong>一些属性</strong>，注解的属性也叫做成员变量，注解只有成员变量，没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明，其方法名定义了该成员变量的名字，其返回值定义了该成员变量的类型：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Target(&#123;ElementType.METHOD, ElementType.TYPE&#125;)</span><br><span class="hljs-meta">@Retention(RetentionPolicy.RUNTIME)</span><br><span class="hljs-keyword">public</span> <span class="hljs-meta">@interface</span> Test &#123;<br>    String <span class="hljs-title function_">value</span><span class="hljs-params">()</span>;<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="8-4-2、默认value可省略"><a href="#8-4-2、默认value可省略" class="headerlink" title="8.4.2、默认value可省略"></a>8.4.2、默认value可省略</h4><p>默认只有一个属性时，我们可以将其名字设定为value，否则，我们需要在使用时手动指定注解的属性名称，使用value则无需填入：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Target(&#123;ElementType.METHOD, ElementType.TYPE&#125;)</span><br><span class="hljs-meta">@Retention(RetentionPolicy.RUNTIME)</span><br><span class="hljs-keyword">public</span> <span class="hljs-meta">@interface</span> Test &#123;<br>    String <span class="hljs-title function_">test</span><span class="hljs-params">()</span>;<br>    <span class="hljs-comment">//属性名为test</span><br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Main</span> &#123;<br>    <span class="hljs-meta">@Test(test = &quot;&quot;)</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>      <span class="hljs-comment">//默认属性名为value</span><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="8-4-3、属性可以设置默认值（使用便不用传值）"><a href="#8-4-3、属性可以设置默认值（使用便不用传值）" class="headerlink" title="8.4.3、属性可以设置默认值（使用便不用传值）"></a>8.4.3、属性可以设置默认值（使用便不用传值）</h4><p>我们也可以使用default关键字来为这些属性指定默认值：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Target(&#123;ElementType.METHOD, ElementType.TYPE&#125;)</span><br><span class="hljs-meta">@Retention(RetentionPolicy.RUNTIME)</span><br><span class="hljs-keyword">public</span> <span class="hljs-meta">@interface</span> Test &#123;<br>    String <span class="hljs-title function_">value</span><span class="hljs-params">()</span> <span class="hljs-keyword">default</span> <span class="hljs-string">&quot;都看到这里了，给个三连吧！&quot;</span>;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>当属性存在默认值时，使用注解的时候可以不用传入属性值。当属性为数组时呢？</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Target(&#123;ElementType.METHOD, ElementType.TYPE&#125;)</span><br><span class="hljs-meta">@Retention(RetentionPolicy.RUNTIME)</span><br><span class="hljs-keyword">public</span> <span class="hljs-meta">@interface</span> Test &#123;<br>    String[] value();<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="8-4-4、属性为数组怎么传入"><a href="#8-4-4、属性为数组怎么传入" class="headerlink" title="8.4.4、属性为数组怎么传入"></a>8.4.4、属性为数组怎么传入</h4><p>当属性为数组，我们在使用注解传参时，如果数组里面只有一个内容，我们可以直接传入一个值，如果有多个内容，我们可以传入数组。：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">//属性只有1个值</span><br><br><span class="hljs-meta">@Test(&quot;关注点了吗&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>  <br>&#125;<br></code></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">//属性有多个值</span><br><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Main</span> &#123;<br>    <span class="hljs-meta">@Test(&#123;&quot;value1&quot;, &quot;value2&quot;&#125;)</span>   <span class="hljs-comment">//多个值时就使用花括号括起来</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="9、-amp-amp-反射获取注解"><a href="#9、-amp-amp-反射获取注解" class="headerlink" title="9、&amp;&amp;反射获取注解"></a>9、&amp;&amp;反射获取注解</h2><h3 id="9-1、类上的注解"><a href="#9-1、类上的注解" class="headerlink" title="9.1、类上的注解"></a>9.1、类上的注解</h3><p>既然我们的注解可以保留到运行时，那么我们来看看，如何获取我们编写的注解，我们需要用到反射机制：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> &#123;<br>    Class&lt;Student&gt; clazz = Student.class;<br>    <span class="hljs-keyword">for</span> (Annotation annotation : clazz.getAnnotations()) &#123;<br>        System.out.println(annotation.annotationType());   <span class="hljs-comment">//获取类型</span><br>        System.out.println(annotation <span class="hljs-keyword">instanceof</span> Test);   <span class="hljs-comment">//直接判断是否为Test</span><br>        <span class="hljs-type">Test</span> <span class="hljs-variable">test</span> <span class="hljs-operator">=</span> (Test) annotation;<br>        System.out.println(test.value());   <span class="hljs-comment">//获取我们在注解中写入的内容</span><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h3 id="9-2、方法上的注解"><a href="#9-2、方法上的注解" class="headerlink" title="9.2、方法上的注解"></a>9.2、方法上的注解</h3><p>通过反射机制，我们可以快速获取到我们标记的注解，同时还能获取到注解中填入的值，那么我们来看看，方法上的标记是不是也可以通过这种方式获取注解：</p>
<p>实际上就多了一个getMethod(“方法名”)</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> NoSuchMethodException &#123;<br>    Class&lt;Student&gt; clazz = Student.class;<br>    <span class="hljs-keyword">for</span> (Annotation annotation : **clazz.getMethod(<span class="hljs-string">&quot;test&quot;</span>)**.getAnnotations()) &#123;<br>        System.out.println(annotation.annotationType());   <span class="hljs-comment">//获取类型</span><br>        System.out.println(annotation <span class="hljs-keyword">instanceof</span> Test);   <span class="hljs-comment">//直接判断是否为Test</span><br>        <span class="hljs-type">Test</span> <span class="hljs-variable">test</span> <span class="hljs-operator">=</span> (Test) annotation;<br>        System.out.println(test.value());   <span class="hljs-comment">//获取我们在注解中写入的内容</span><br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<p>无论是方法、类、还是字段，都可以使用<code>getAnnotations()</code>方法（还有几个同名的）来快速获取我们标记的注解。</p>

              
            </div>
            <hr/>
            <div>
              <div class="post-metas my-3">
  
    <div class="post-meta mr-3 d-flex align-items-center">
      <i class="iconfont icon-category"></i>
      

<span class="category-chains">
  
  
    
      <span class="category-chain">
        
  <a href="/categories/%E5%BC%80%E5%8F%91/" class="category-chain-item">开发</a>
  
  

      </span>
    
  
</span>

    </div>
  
  
    <div class="post-meta">
      <i class="iconfont icon-tags"></i>
      
        <a href="/tags/Java/">#Java</a>
      
    </div>
  
</div>


              
  

  <div class="license-box my-3">
    <div class="license-title">
      <div>关于反射与注解的理解与总结</div>
      <div>http://example.com/2022/06/19/关于反射与注解的理解与总结/</div>
    </div>
    <div class="license-meta">
      
        <div class="license-meta-item">
          <div>作者</div>
          <div>Wahoyu</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>发布于</div>
          <div>2022年6月19日</div>
        </div>
      
      
      <div class="license-meta-item">
        <div>许可协议</div>
        <div>
          
            
            
              <a target="_blank" href="https://creativecommons.org/licenses/by/4.0/">
              <span class="hint--top hint--rounded" aria-label="BY - 署名">
                <i class="iconfont icon-by"></i>
              </span>
              </a>
            
          
        </div>
      </div>
    </div>
    <div class="license-icon iconfont"></div>
  </div>



              
                <div class="post-prevnext my-3">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2022/06/27/%E5%9F%BA%E4%BA%8EMybatis-JUL-Lombok-Maven%E7%9A%84%E5%9B%BE%E4%B9%A6%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%EF%BC%88%E5%B8%A6%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95%EF%BC%89/" title="基于Mybatis的图书管理系统">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">基于Mybatis的图书管理系统</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2022/06/10/%E7%AE%80%E5%8D%95%E7%AE%97%E6%B3%95%EF%BC%88Java%E5%AE%9E%E7%8E%B0%EF%BC%89/" title="排序与搜索算法（Java实现）">
                        <span class="hidden-mobile">排序与搜索算法（Java实现）</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
  <article id="comments" lazyload>
    
  <div id="valine"></div>
  <script type="text/javascript">
    Fluid.utils.loadComments('#valine', function() {
      Fluid.utils.createScript('https://lib.baomitu.com/valine/1.4.16/Valine.min.js', function() {
        var options = Object.assign(
          {"appId":"7WuaJQGQGU5GFxMKMtDzWYVI-gzGzoHsz","appKey":"zdCzx5CuURztPQQoi8LuXSWv","path":"window.location.pathname","placeholder":"请留下您的想法...","avatar":"retro","meta":["nick","mail","link"],"requiredFields":[],"pageSize":10,"lang":"zh-CN","highlight":false,"recordIP":true,"serverURLs":"https://7wuajqgq.lc-cn-n1-shared.com","emojiCDN":null,"emojiMaps":null,"enableQQ":true},
          {
            el: "#valine",
            path: window.location.pathname
          }
        )
        new Valine(options);
        Fluid.utils.waitElementVisible('#valine .vcontent', () => {
          var imgSelector = '#valine .vcontent img:not(.vemoji)';
          Fluid.plugins.imageCaption(imgSelector);
          Fluid.plugins.fancyBox(imgSelector);
        })
      });
    });
  </script>
  <noscript>Please enable JavaScript to view the comments</noscript>


  </article>


          </article>
        </div>
      </div>
    </div>

    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar" style="margin-left: -1rem">
    <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>



  </aside>


    </div>
  </div>
</div>





  



  



  



  



  






    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v" for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>

    

    
  </main>

  <footer>
    <div class="footer-inner">
  
    <div class="footer-content">
       <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a> <i class="iconfont icon-love"></i> <text>哆啦是个梦</text> <div style="font-size: 0.85rem"> <span id="timeDate">载入天数...</span> <span id="times">载入时分秒...</span> <script src="/js/duration.js"></script> </div> 
    </div>
  
  
  
  
</div>

  </footer>

  <!-- Scripts -->
  
  <script  src="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js" ></script>
<script  src="https://lib.baomitu.com/twitter-bootstrap/4.6.1/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>


  <script  src="https://lib.baomitu.com/typed.js/2.0.12/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var subtitle = document.getElementById('subtitle');
      if (!subtitle || !typing) {
        return;
      }
      var text = subtitle.getAttribute('data-typed-text');
      
        typing(text);
      
    })(window, document);
  </script>




  

  

  

  

  

  

  




  
    <script  src="/js/img-lazyload.js" ></script>
  




  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/tocbot/4.18.0/tocbot.min.js', function() {
    var toc = jQuery('#toc');
    if (toc.length === 0 || !window.tocbot) { return; }
    var boardCtn = jQuery('#board-ctn');
    var boardTop = boardCtn.offset().top;

    window.tocbot.init({
      tocSelector     : '#toc-body',
      contentSelector : '.markdown-body',
      headingSelector : CONFIG.toc.headingSelector || 'h1,h2,h3,h4,h5,h6',
      linkClass       : 'tocbot-link',
      activeLinkClass : 'tocbot-active-link',
      listClass       : 'tocbot-list',
      isCollapsedClass: 'tocbot-is-collapsed',
      collapsibleClass: 'tocbot-is-collapsible',
      collapseDepth   : CONFIG.toc.collapseDepth || 0,
      scrollSmooth    : true,
      headingsOffset  : -boardTop
    });
    if (toc.find('.toc-list-item').length > 0) {
      toc.css('visibility', 'visible');
    }
  });
</script>


  <script>
  (function() {
    var enableLang = CONFIG.code_language.enable && CONFIG.code_language.default;
    var enableCopy = CONFIG.copy_btn;
    if (!enableLang && !enableCopy) {
      return;
    }

    function getBgClass(ele) {
      return Fluid.utils.getBackgroundLightness(ele) >= 0 ? 'code-widget-light' : 'code-widget-dark';
    }

    var copyTmpl = '';
    copyTmpl += '<div class="code-widget">';
    copyTmpl += 'LANG';
    copyTmpl += '</div>';
    jQuery('.markdown-body pre').each(function() {
      var $pre = jQuery(this);
      if ($pre.find('code.mermaid').length > 0) {
        return;
      }
      if ($pre.find('span.line').length > 0) {
        return;
      }

      var lang = '';

      if (enableLang) {
        lang = CONFIG.code_language.default;
        if ($pre[0].children.length > 0 && $pre[0].children[0].classList.length >= 2 && $pre.children().hasClass('hljs')) {
          lang = $pre[0].children[0].classList[1];
        } else if ($pre[0].getAttribute('data-language')) {
          lang = $pre[0].getAttribute('data-language');
        } else if ($pre.parent().hasClass('sourceCode') && $pre[0].children.length > 0 && $pre[0].children[0].classList.length >= 2) {
          lang = $pre[0].children[0].classList[1];
          $pre.parent().addClass('code-wrapper');
        } else if ($pre.parent().hasClass('markdown-body') && $pre[0].classList.length === 0) {
          $pre.wrap('<div class="code-wrapper"></div>');
        }
        lang = lang.toUpperCase().replace('NONE', CONFIG.code_language.default);
      }
      $pre.append(copyTmpl.replace('LANG', lang).replace('code-widget">',
        getBgClass($pre[0]) + (enableCopy ? ' code-widget copy-btn" data-clipboard-snippet><i class="iconfont icon-copy"></i>' : ' code-widget">')));

      if (enableCopy) {
        Fluid.utils.createScript('https://lib.baomitu.com/clipboard.js/2.0.10/clipboard.min.js', function() {
          var clipboard = new window.ClipboardJS('.copy-btn', {
            target: function(trigger) {
              var nodes = trigger.parentNode.childNodes;
              for (var i = 0; i < nodes.length; i++) {
                if (nodes[i].tagName === 'CODE') {
                  return nodes[i];
                }
              }
            }
          });
          clipboard.on('success', function(e) {
            e.clearSelection();
            e.trigger.innerHTML = e.trigger.innerHTML.replace('icon-copy', 'icon-success');
            setTimeout(function() {
              e.trigger.innerHTML = e.trigger.innerHTML.replace('icon-success', 'icon-copy');
            }, 2000);
          });
        });
      }
    });
  })();
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/anchor-js/4.3.1/anchor.min.js', function() {
    window.anchors.options = {
      placement: CONFIG.anchorjs.placement,
      visible  : CONFIG.anchorjs.visible
    };
    if (CONFIG.anchorjs.icon) {
      window.anchors.options.icon = CONFIG.anchorjs.icon;
    }
    var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
    var res = [];
    for (var item of el) {
      res.push('.markdown-body > ' + item.trim());
    }
    if (CONFIG.anchorjs.placement === 'left') {
      window.anchors.options.class = 'anchorjs-link-left';
    }
    window.anchors.add(res.join(', '));
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js', function() {
    Fluid.plugins.fancyBox();
  });
</script>


  <script>Fluid.plugins.imageCaption();</script>

  <script  src="/js/local-search.js" ></script>

  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>




  
<script src="//cdn.jsdelivr.net/gh/bynotes/texiao/source/js/xiantiao.js"></script>



<!-- 主题的启动项，将它保持在最底部 -->
<!-- the boot of the theme, keep it at the bottom -->
<script  src="/js/boot.js" ></script>


  

  <noscript>
    <div class="noscript-warning">博客在允许 JavaScript 运行的环境下浏览效果更佳</div>
  </noscript>
</body>
</html>
